package com.butterfly.hotkey.common.factory;

import cn.hutool.core.util.StrUtil;
import com.butterfly.hotkey.core.constant.Constants;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.annotation.AnnotationUtils;

import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 工厂加载器
 *
 * @author butterfly
 */
public class CommonFactory implements ApplicationListener<ContextRefreshedEvent> {

    private static final Logger log = LoggerFactory.getLogger(Constants.WORKER);

    /**
     * 存储系统内所有的工厂类
     */
    private static final Map<String, Object> FACTORY_BEAN_MAP = new ConcurrentHashMap<>(16);

    private static final Map<String, List<Object>> FACTORY_TYPE_MAP = new ConcurrentHashMap<>(16);

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        ApplicationContext applicationContext = event.getApplicationContext();
        Map<String, Object> beansOfType = applicationContext.getBeansWithAnnotation(CommonFactoryBean.class);
        for (Map.Entry<String, Object> entry : beansOfType.entrySet()) {
            Object iCommonFactoryBean = entry.getValue();
            CommonFactoryBean commonFactoryBean = AnnotationUtils.getAnnotation(iCommonFactoryBean.getClass(), CommonFactoryBean.class);
            if (commonFactoryBean != null) {
                String value = getBeanValue(commonFactoryBean);

                String factoryType = commonFactoryBean.type();
                String mapKey = getCacheKey(value, factoryType);
                FACTORY_BEAN_MAP.put(mapKey, iCommonFactoryBean);
                List<Object> beans = FACTORY_TYPE_MAP.getOrDefault(factoryType, Lists.newArrayList());
                beans.add(iCommonFactoryBean);
                FACTORY_TYPE_MAP.put(factoryType, beans);

                if (log.isDebugEnabled()) {
                    log.debug("build commonFactoryBean:{}", commonFactoryBean);
                }
            } else {
                log.warn("build commonFactoryBean fail, annotation is null:{}", iCommonFactoryBean);
            }
        }
    }

    private static String getBeanValue(CommonFactoryBean commonFactoryBean) {
        String valueStr = commonFactoryBean.valueStr();
        int valueInt = commonFactoryBean.valueInt();
        String value;
        if (valueInt == -1) {
            value = valueStr;
        } else {
            value = String.valueOf(valueInt);
        }
        return value;
    }

    /**
     * 构建缓存Map的Key
     *
     * @param value       value
     * @param factoryType factoryType
     * @return String
     */
    private static String getCacheKey(String value, String factoryType) {
        return value + StrUtil.UNDERLINE + factoryType;
    }

    /**
     * 使用方保证能转换
     *
     * @param factoryType factoryType
     * @param <T>         <T>
     * @return 工厂类
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String factoryType, Serializable annotationKey) {
        String mapKey = getCacheKey(String.valueOf(annotationKey), factoryType);
        Object bean = FACTORY_BEAN_MAP.get(mapKey);
        return (T) bean;
    }

    /**
     * 使用方保证能转换
     *
     * @param factoryType factoryType
     * @param <T>         <T>
     * @return 工厂类
     */
    @SuppressWarnings("unchecked")
    public static <T> List<T> getBeanList(String factoryType) {
        return (List<T>) FACTORY_TYPE_MAP.get(factoryType);
    }


}
